﻿///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2023, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Область СлужебныйПрограммныйИнтерфейс

// Возвращает флаг доступности действий изменения пользователей.
//
// Возвращаемое значение:
//   Булево - Истина, если изменение пользователей доступно, иначе Ложь.
//
Функция ДоступноИзменениеПользователей() Экспорт
	
	Если ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда
		МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
		Возврат МодульРаботаВМоделиСервиса.ДоступноИзменениеПользователей();
	КонецЕсли;
	Возврат Ложь;
	
КонецФункции

// Возвращает доступные текущему пользователю действия с указанным
// пользователем сервиса.
//
// Параметры:
//  Пользователь - СправочникСсылка.Пользователи - пользователь, доступные
//   действия с которым требуется получить. Если не указано, проверяются
//   доступные действия с текущим пользователем.
//  
// Возвращаемое значение:
//   см. НовыеДействияСПользователемСервиса
//
Функция ПолучитьДействияСПользователемСервиса(Знач Пользователь = Неопределено) Экспорт
	
	Если Пользователь = Неопределено Тогда
		Пользователь = Пользователи.ТекущийПользователь();
	КонецЕсли;
	
	Если Не ДоступноИзменениеПользователей() Тогда
		Возврат ДействияСПользователемСервисаПриНедоступностиНастройкиПользователей();
	КонецЕсли;
		
	Если ПользователиИнформационнойБазы.ТекущийПользователь().РазделениеДанных.Количество() = 0 Тогда
		Если Пользователи.ЭтоПолноправныйПользователь(, Истина) Тогда
			Возврат ДействияСНовымПользователемСервиса();
		Иначе
			Возврат ДействияСПользователемСервисаПриНедоступностиНастройкиПользователей();
		КонецЕсли;
		
	ИначеЕсли ЭтоСуществующийПользовательТекущейОбластиДанных(Пользователь) Тогда
		Возврат ДействияССуществующимПользователемСервиса(Пользователь);
	Иначе
		Если ЕстьПравоДобавленияПользователей() Тогда
			Возврат ДействияСНовымПользователемСервиса();
		Иначе
			ТекстОшибки = НСтр("ru = 'Недостаточно прав доступа для добавления новых пользователей'");
			ВызватьИсключение ТекстОшибки;
		КонецЕсли;
	КонецЕсли;
	
КонецФункции

// Формирует запрос на изменение адреса электронной почты пользователя
// сервиса.
//
// Параметры:
//  НоваяПочта - Строка - новый адрес электронной почты пользователя.
//  Пользователь - СправочникСсылка.Пользователи - пользователь, которому
//   требуется изменить адрес электронной почты.
//  ПарольПользователяСервиса - Строка - пароль текущего пользователя
//   для доступа к менеджеру сервиса.
//
Процедура СоздатьЗапросНаСменуПочты(Знач НоваяПочта, Знач Пользователь, Знач ПарольПользователяСервиса) Экспорт
	
	Если Не ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда
		Возврат;
	КонецЕсли;
	
	МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
	
	УстановитьПривилегированныйРежим(Истина);
	Прокси = МодульРаботаВМоделиСервиса.ПолучитьПроксиМенеджераСервиса(ПарольПользователяСервиса);
	УстановитьПривилегированныйРежим(Ложь);
	
	ИнформацияОбОшибке = Неопределено;
	Прокси.RequestEmailChange(
		ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Пользователь, "ИдентификаторПользователяСервиса"), 
		НоваяПочта, 
		ИнформацияОбОшибке);
	ОбработатьИнформациюОбОшибкеWebСервиса(ИнформацияОбОшибке, "RequestEmailChange"); 
	
КонецПроцедуры

// Создает / обновляет запись пользователя сервиса.
// 
// Параметры:
//  Пользователь - СправочникСсылка.Пользователи
//               - СправочникОбъект.Пользователи
//
//  СоздатьПользователяСервиса - Булево
//     Истина - создать нового пользователя сервиса,
//     Ложь - обновить существующего.
//
//  ПарольПользователяСервиса - Строка - пароль текущего пользователя
//   для доступа к менеджеру сервиса.
//
Процедура ЗаписатьПользователяСервиса(Знач Пользователь, Знач СоздатьПользователяСервиса, Знач ПарольПользователяСервиса) Экспорт
	
	Если Не ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда
		Возврат;
	КонецЕсли;
	
	Если ТипЗнч(Пользователь) = Тип("СправочникСсылка.Пользователи") Тогда
		ПользовательОбъект = Пользователь.ПолучитьОбъект();
	Иначе
		ПользовательОбъект = Пользователь;
	КонецЕсли;
	
	МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
	
	УстановитьПривилегированныйРежим(Истина);
	Прокси = МодульРаботаВМоделиСервиса.ПолучитьПроксиМенеджераСервиса(ПарольПользователяСервиса);
	УстановитьПривилегированныйРежим(Ложь);
	
	Если ЗначениеЗаполнено(ПользовательОбъект.ИдентификаторПользователяИБ) Тогда
		ПользовательИБ = ПользователиИнформационнойБазы.НайтиПоУникальномуИдентификатору(ПользовательОбъект.ИдентификаторПользователяИБ);
		ДоступРазрешен = ВозможенЗапускПриложения(ПользовательИБ);
	Иначе
		ДоступРазрешен = Ложь;
	КонецЕсли;
	
	ПользовательСервиса = Прокси.ФабрикаXDTO.Создать(
		Прокси.ФабрикаXDTO.Тип("http://www.1c.ru/SaaS/ApplicationUsers", "User"));
	ПользовательСервиса.Zone = МодульРаботаВМоделиСервиса.ЗначениеРазделителяСеанса();
	ПользовательСервиса.UserServiceID = ПользовательОбъект.ИдентификаторПользователяСервиса;
	ПользовательСервиса.FullName = ПользовательОбъект.Наименование;
	ПользовательСервиса.Name = ПользовательИБ.Имя;
	ПользовательСервиса.StoredPasswordValue = ПользовательИБ.СохраняемоеЗначениеПароля;
	ПользовательСервиса.Language = ПолучитьКодЯзыка(ПользовательИБ.Язык);
	ПользовательСервиса.Access = ДоступРазрешен;
	ПользовательСервиса.AdmininstrativeAccess = ДоступРазрешен И ПользовательИБ.Роли.Содержит(Метаданные.Роли.ПолныеПрава);
	
	КонтактнаяИнформация = Прокси.ФабрикаXDTO.Создать(
		Прокси.ФабрикаXDTO.Тип("http://www.1c.ru/SaaS/ApplicationUsers", "ContactsList"));
		
	ТипЗаписьКИ = Прокси.ФабрикаXDTO.Тип("http://www.1c.ru/SaaS/ApplicationUsers", "ContactsItem");
	
	СоответствиеВидовКИ = МодульРаботаВМоделиСервиса.СоответствиеВидовКИПользователяXDTO();
	Для каждого СтрокаКИ Из ПользовательОбъект.КонтактнаяИнформация Цикл
		ВидКИXDTO = СоответствиеВидовКИ.Получить(СтрокаКИ.Вид);
		Если ВидКИXDTO = Неопределено Тогда
			Продолжить;
		КонецЕсли;
		
		ЗаписьКИ = Прокси.ФабрикаXDTO.Создать(ТипЗаписьКИ);
		ЗаписьКИ.ContactType = ВидКИXDTO;
		ЗаписьКИ.Value = СтрокаКИ.Представление;
		ЗаписьКИ.Parts = СтрокаКИ.ЗначенияПолей;
		
		ЗаписиКИ = КонтактнаяИнформация.Item; // СписокXDTO
		ЗаписиКИ.Добавить(ЗаписьКИ);
	КонецЦикла;
	
	ПользовательСервиса.Contacts = КонтактнаяИнформация;
	
	ИнформацияОбОшибке = Неопределено;
	Если СоздатьПользователяСервиса Тогда
		Прокси.CreateUser(ПользовательСервиса, ИнформацияОбОшибке);
		ОбработатьИнформациюОбОшибкеWebСервиса(ИнформацияОбОшибке, "CreateUser"); 
	Иначе
		Прокси.UpdateUser(ПользовательСервиса, ИнформацияОбОшибке);
		ОбработатьИнформациюОбОшибкеWebСервиса(ИнформацияОбОшибке, "UpdateUser"); 
	КонецЕсли;
	
КонецПроцедуры

// Отправляет сообщение менеджеру сервиса об изменении возможности запуска приложения
// (наличия разрешения и прав для входа в программу).
// 
// Параметры:
//  Пользователь - СправочникСсылка.Пользователи
//  ПользовательИБ - ПользовательИнформационнойБазы
//  СтарыйПользовательИБ - Неопределено - отправить безусловно
//                       - ПользовательИнформационнойБазы - отправить, если изменен.
//
Процедура СообщитьИзмененЗапускПриложения(Пользователь, ПользовательИБ, СтарыйПользовательИБ = Неопределено) Экспорт
	
	Если Не ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность")
	 Или Не ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.ОбменСообщениями")
	 Или Не ПоддерживаютсяСообщенияЕстьПраваДляВходаВПрограмму() Тогда
		Возврат;
	КонецЕсли;
	
	ВозможенЗапуск = ВозможенЗапускПриложения(ПользовательИБ);
	Если СтарыйПользовательИБ <> Неопределено
	   И ВозможенЗапуск = ВозможенЗапускПриложения(СтарыйПользовательИБ) Тогда
		Возврат;
	КонецЕсли;
	
	Реквизиты = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(Пользователь,
		"ИдентификаторПользователяИБ, ИдентификаторПользователяСервиса");
	
	МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
	МодульОбменСообщениями = ОбщегоНазначения.ОбщийМодуль("ОбменСообщениями");
	
	ИнфоПользователя = Новый Структура;
	ИнфоПользователя.Вставить("ОбластьДанных", МодульРаботаВМоделиСервиса.ЗначениеРазделителяСеанса());
	ИнфоПользователя.Вставить("ИдентификаторПользователяИБ", Реквизиты.ИдентификаторПользователяИБ);
	ИнфоПользователя.Вставить("ИдентификаторПользователяСервиса", Реквизиты.ИдентификаторПользователяСервиса);
	ИнфоПользователя.Вставить("ЕстьПрава", ВозможенЗапуск);
	ИнфоПользователя.Вставить("ДатаUTC", ТекущаяУниверсальнаяДата());
	
	НачатьТранзакцию();
	Попытка
		МодульОбменСообщениями.ОтправитьСообщение("UserHandler/LaunchSwitch", ОбщегоНазначения.ЗначениеВСтрокуXML(
			ИнфоПользователя), МодульРаботаВМоделиСервиса.КонечнаяТочкаМенеджераСервиса());
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
КонецПроцедуры

#Область РаботаСНеразделеннымиПользователямиИнформационнойБазы

// Вызывается перед запуском программы до вызова всех остальных обработчиков.
Процедура ПередЗапускомПрограммы() Экспорт
	
	Если ЭтоНеразделенныйПользовательИБ() Тогда
		ЗарегистрироватьНеразделенногоПользователяВРегистре();
	КонецЕсли;
	
КонецПроцедуры

// Проверяет содержится ли пользователь ИБ с заданным идентификатором
// в списке неразделенных пользователей.
//
// Параметры:
//   ИдентификаторПользователяИБ - УникальныйИдентификатор - идентификатор
//        пользователя ИБ, для которого нужно проверить
//        принадлежность к неразделенным пользователям.
//
// Возвращаемое значение:
//  Булево
//
Функция ПользовательЗарегистрированКакНеразделенный(Знач ИдентификаторПользователяИБ) Экспорт
	
	Если НЕ ЗначениеЗаполнено(ИдентификаторПользователяИБ) Тогда
		Возврат Ложь;
	КонецЕсли;
	
	УстановитьПривилегированныйРежим(Истина);
	
	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ
	|	ИДНеразделенныхПользователей.ИдентификаторПользователяИБ
	|ИЗ
	|	РегистрСведений.НеразделенныеПользователи КАК ИДНеразделенныхПользователей
	|ГДЕ
	|	ИДНеразделенныхПользователей.ИдентификаторПользователяИБ = &ИдентификаторПользователяИБ";
	Запрос.УстановитьПараметр("ИдентификаторПользователяИБ", ИдентификаторПользователяИБ);
	
	Блокировка = Новый БлокировкаДанных;
	ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.НеразделенныеПользователи");
	ЭлементБлокировки.УстановитьЗначение("ИдентификаторПользователяИБ", ИдентификаторПользователяИБ);
	ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый;
	
	НачатьТранзакцию();
	Попытка
		Блокировка.Заблокировать();
		Результат = Запрос.Выполнить();
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
	Возврат НЕ Результат.Пустой();
	
КонецФункции

#КонецОбласти

#Область ОбработчикиСобытийПодсистемКонфигурации

// См. ИнтеграцияПодсистемБСП.ПриОтсутствииТекущегоПользователяВСправочнике
Процедура ПриОтсутствииТекущегоПользователяВСправочнике(СоздатьПользователя) Экспорт
	
	Если ЭтоНеразделенныйПользовательИБ() Тогда
		// Для всех неразделенных пользователей требуется автоматически
		// создавать пользователя в справочнике Пользователи текущей области данных.
		СоздатьПользователя = Истина;
	КонецЕсли;
	
КонецПроцедуры

// См. ИнтеграцияПодсистемБСП.ПриАвтоматическомСозданииТекущегоПользователяВСправочнике
Процедура ПриАвтоматическомСозданииТекущегоПользователяВСправочнике(НовыйПользователь) Экспорт
	
	Если ЭтоНеразделенныйПользовательИБ() Тогда
		НовыйПользователь.Служебный = Истина;
		НовыйПользователь.Наименование = ПолноеИмяСлужебногоПользователя(
			ПользователиИнформационнойБазы.ТекущийПользователь().УникальныйИдентификатор);
	КонецЕсли;
	
КонецПроцедуры

// См. ИнтеграцияПодсистемБСП.ПриАвторизацииНовогоПользователяИБ
Процедура ПриАвторизацииНовогоПользователяИБ(Знач ТекущийПользовательИБ, СтандартнаяОбработка) Экспорт
	
	Если Не ОбщегоНазначения.РазделениеВключено()
		Или Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
		Возврат;
	КонецЕсли;
	
	Если Не ЭтоНеразделенныйПользовательИБ() Тогда
		Возврат;
	КонецЕсли;
			
	СтандартнаяОбработка = Ложь;
	
	НачатьТранзакцию();
	Попытка
		
		Блокировка = Новый БлокировкаДанных();
		Блокировка.Добавить("Справочник.Пользователи");
		Блокировка.Заблокировать();
		
		Если Не ПользователиСлужебный.ПользовательПоИдентификаторуСуществует(ТекущийПользовательИБ.УникальныйИдентификатор) Тогда
			
			// Это неразделенный пользователь, требуется создать элемент в текущей области.
			ПользовательОбъект = Справочники.Пользователи.СоздатьЭлемент();
			ПользовательОбъект.Наименование = ПолноеИмяСлужебногоПользователя(ТекущийПользовательИБ.УникальныйИдентификатор);
			ПользовательОбъект.Служебный = Истина;
			ПользовательОбъект.Записать();
			
			ПользовательОбъект.ИдентификаторПользователяИБ = ТекущийПользовательИБ.УникальныйИдентификатор;
			ПользовательОбъект.ОбменДанными.Загрузка = Истина;
			ПользовательОбъект.Записать();
			
		КонецЕсли;
		
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
		
КонецПроцедуры

// См. ИнтеграцияПодсистемБСП.ПриНачалеОбработкиПользователяИБ
Процедура ПриНачалеОбработкиПользователяИБ(ПараметрыОбработки, ОписаниеПользователяИБ) Экспорт
	
	Если ЗначениеЗаполнено(ПараметрыОбработки.СтарыйПользователь.ИдентификаторПользователяИБ)
	   И ОбщегоНазначения.РазделениеВключено()
	   И ПользовательЗарегистрированКакНеразделенный(
	         ПараметрыОбработки.СтарыйПользователь.ИдентификаторПользователяИБ) Тогда
		
		ВызватьИсключение ТекстИсключенияЗаписьНеразделенныхПользователейЗапрещена();
		
	ИначеЕсли ОписаниеПользователяИБ.Свойство("УникальныйИдентификатор")
	        И ЗначениеЗаполнено(ОписаниеПользователяИБ.УникальныйИдентификатор)
	        И ОбщегоНазначения.РазделениеВключено()
	        И ПользовательЗарегистрированКакНеразделенный(
	              ОписаниеПользователяИБ.УникальныйИдентификатор) Тогда
		
		// Исключаем перезапись пользователя информационной базы при записи элементов
		// справочника "Пользователя", соответствующих неразделенным пользователям.
		ПараметрыОбработки.Удалить("Действие");
		
		Если ОписаниеПользователяИБ.Количество() > 2
		 ИЛИ ОписаниеПользователяИБ.Действие = "Удалить" Тогда
			
			ВызватьИсключение ТекстИсключенияЗаписьНеразделенныхПользователейЗапрещена();
		КонецЕсли;
	КонецЕсли;
	
КонецПроцедуры

// См. ИнтеграцияПодсистемБСП.ПередЗаписьюПользователяИБ
Процедура ПередЗаписьюПользователяИБ(ПользовательИБ) Экспорт
	
	Если ОбщегоНазначения.РазделениеВключено() Тогда
		Если ПользовательЗарегистрированКакНеразделенный(ПользовательИБ.УникальныйИдентификатор) Тогда
			ВызватьИсключение ТекстИсключенияЗаписьНеразделенныхПользователейЗапрещена();
		КонецЕсли;
	КонецЕсли;
	
КонецПроцедуры

// Обработка пользователя ИБ в ходе записи элемента справочника Пользователи и ВнешниеПользователи.
// Вызывается из процедуры НачатьОбработкуПользователяИБ для поддержки модели сервиса.
// 
// Параметры:
//  ПользовательОбъект - СправочникОбъект.Пользователи
//                     - СправочникОбъект.ВнешниеПользователи
//  ПараметрыОбработки - Структура
//
Процедура ПередНачаломОбработкиПользователяИБ(Знач ПользовательОбъект, ПараметрыОбработки) Экспорт
	
	Если Не ОбщегоНазначения.РазделениеВключено() Тогда
		Возврат;
	КонецЕсли;
	
	ДополнительныеСвойства = ПользовательОбъект.ДополнительныеСвойства;
	СтарыйПользователь     = ПараметрыОбработки.СтарыйПользователь;
	АвтоРеквизиты          = ПараметрыОбработки.АвтоРеквизиты;
	
	Если ТипЗнч(ПользовательОбъект) = Тип("СправочникОбъект.ВнешниеПользователи") Тогда
		ТекстОшибки = НСтр("ru = 'Внешние пользователи не поддерживаются в модели сервиса.'");
		ВызватьИсключение ТекстОшибки;
	КонецЕсли;
	
	АвтоРеквизиты.Вставить("ИдентификаторПользователяСервиса", СтарыйПользователь.ИдентификаторПользователяСервиса);
	
	Если ДополнительныеСвойства.Свойство("ОбработкаСообщенияКаналаУдаленногоАдминистрирования") Тогда
		
		МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
		Если НЕ МодульРаботаВМоделиСервиса.СеансЗапущенБезРазделителей() Тогда
			ТекстОшибки =
				НСтр("ru = 'Изменение сведений о пользователях через удаленное администрирование
				           |доступно только неразделенным пользователям.'");
			ВызватьИсключение ТекстОшибки;
		КонецЕсли;
		
		ПараметрыОбработки.Вставить("ОбработкаСообщенияКаналаУдаленногоАдминистрирования");
		АвтоРеквизиты.ИдентификаторПользователяСервиса = ПользовательОбъект.ИдентификаторПользователяСервиса;
		
	ИначеЕсли НЕ ПользовательОбъект.Служебный Тогда
		ОбновитьОписаниеWebСервисаМенеджераСервиса();
	КонецЕсли;
	
	Если ЗначениеЗаполнено(АвтоРеквизиты.ИдентификаторПользователяСервиса)
	   И АвтоРеквизиты.ИдентификаторПользователяСервиса <> СтарыйПользователь.ИдентификаторПользователяСервиса Тогда
		
		Если ЗначениеЗаполнено(СтарыйПользователь.ИдентификаторПользователяСервиса) Тогда
			ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Запрещено изменять идентификатор пользователя сервиса для ""%1"".'"),
				ПользовательОбъект.Наименование);
			ВызватьИсключение ТекстОшибки;
		КонецЕсли;
		
		НайденныйПользователь = Неопределено;
		
		Если ПользователиСлужебный.ПользовательПоИдентификаторуСуществует(
				АвтоРеквизиты.ИдентификаторПользователяСервиса,
				ПользовательОбъект.Ссылка,
				НайденныйПользователь,
				Истина) Тогда
			
			ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Запрещено устанавливать идентификатор пользователя сервиса ""%1"" для ""%2"",
				           |т.к. он уже указан в другом ""%3"".'"),
				АвтоРеквизиты.ИдентификаторПользователяСервиса,
				ПользовательОбъект.Наименование,
				НайденныйПользователь);
			ВызватьИсключение ТекстОшибки;
		КонецЕсли;
	КонецЕсли;
	
КонецПроцедуры

// Вызывается из процедуры НачатьОбработкуПользователяИБ для поддержки модели сервиса.
//
// Параметры:
//  ПользовательОбъект - СправочникОбъект.Пользователи
//                     - СправочникОбъект.ВнешниеПользователи
//  ПараметрыОбработки - Структура
//
Процедура ПослеНачалаОбработкиПользователяИБ(ПользовательОбъект, ПараметрыОбработки) Экспорт
	
	Если Не ОбщегоНазначения.РазделениеВключено() Тогда
		Возврат;
	КонецЕсли;
	
	АвтоРеквизиты = ПараметрыОбработки.АвтоРеквизиты;
	
	ПараметрыОбработки.Вставить("СоздатьПользователяСервиса", Ложь);
	
	Если ПараметрыОбработки.НовыйПользовательИБСуществует
		И ОбщегоНазначения.РазделениеВключено() Тогда
		
		Если НЕ ЗначениеЗаполнено(АвтоРеквизиты.ИдентификаторПользователяСервиса) Тогда
			
			ПараметрыОбработки.Вставить("СоздатьПользователяСервиса", Истина);
			ПользовательОбъект.ИдентификаторПользователяСервиса = Новый УникальныйИдентификатор;
			
			// Обновление значения реквизита контролируемого при записи.
			АвтоРеквизиты.ИдентификаторПользователяСервиса = ПользовательОбъект.ИдентификаторПользователяСервиса;
		КонецЕсли;
	КонецЕсли;
	
КонецПроцедуры

// Вызывается из процедуры ЗавершитьОбработкуПользователяИБ для поддержки модели сервиса.
//
// Параметры:
//  ПользовательОбъект - СправочникОбъект.Пользователи
//                     - СправочникОбъект.ВнешниеПользователи
//  ПараметрыОбработки - Структура
//
Процедура ПередЗавершениемОбработкиПользователяИБ(ПользовательОбъект, ПараметрыОбработки) Экспорт
	
	Если Не ОбщегоНазначения.РазделениеВключено() Тогда
		Возврат;
	КонецЕсли;
	
	АвтоРеквизиты = ПараметрыОбработки.АвтоРеквизиты;	
	Если АвтоРеквизиты.ИдентификаторПользователяСервиса <> ПользовательОбъект.ИдентификаторПользователяСервиса Тогда
		ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не допускается изменять реквизит %1 для ""%2"".
			           |Значение реквизита обновится автоматически.'"),
			"ИдентификаторПользователяСервиса", ПользовательОбъект.Ссылка);
		ВызватьИсключение ТекстОшибки;
	КонецЕсли;
	
КонецПроцедуры

// Вызывается из процедуры ЗавершитьОбработкуПользователяИБ для поддержки модели сервиса.
// 
// Параметры:
//  ПользовательОбъект - СправочникОбъект.Пользователи
//                     - СправочникОбъект.ВнешниеПользователи
//  ПараметрыОбработки - Структура
//  ОбновлятьРоли      - Булево - возвращаемое значение.
//
Процедура ПриЗавершенииОбработкиПользователяИБ(ПользовательОбъект, ПараметрыОбработки, ОбновлятьРоли) Экспорт
	
	Если Не ОбщегоНазначения.РазделениеВключено() Тогда
		Возврат;
	КонецЕсли;
	
	Если ПараметрыОбработки.Свойство("ОбработкаСообщенияКаналаУдаленногоАдминистрирования") Тогда
		ОбновлятьРоли = Ложь;
		Возврат;
	КонецЕсли;
	
	ОписаниеПользователяИБ = ПользовательОбъект.ДополнительныеСвойства.ОписаниеПользователяИБ;
	
	Если ТипЗнч(ПользовательОбъект) = Тип("СправочникОбъект.Пользователи")
	   И ОписаниеПользователяИБ.Свойство("РезультатДействия")
	   И НЕ ПользовательОбъект.Служебный Тогда
		
		Если ОписаниеПользователяИБ.РезультатДействия = "УдаленПользовательИБ" Тогда
			
			УстановитьПривилегированныйРежим(Истина);
			АннулироватьДоступПользователяСервиса(ПользовательОбъект);
			УстановитьПривилегированныйРежим(Ложь);
			
		Иначе // ДобавленПользовательИБ или ИзмененПользовательИБ.
			
			УстановитьПривилегированныйРежим(Истина);
			Если ПользовательОбъект.ДополнительныеСвойства.Свойство("СинхронизироватьССервисом")
			   И ПользовательОбъект.ДополнительныеСвойства.СинхронизироватьССервисом Тогда
				
				ЗаписатьПользователяСервиса(ПользовательОбъект,
					ПараметрыОбработки.СоздатьПользователяСервиса,
					ПользовательОбъект.ДополнительныеСвойства.ПарольПользователяСервиса);
			Иначе
				СообщитьИзмененЗапускПриложения(ПользовательОбъект.Ссылка,
					ПараметрыОбработки.НовыйПользовательИБ,
					ПараметрыОбработки.СтарыйПользовательИБ);
			КонецЕсли;
			УстановитьПривилегированныйРежим(Ложь);
			
			Если ПараметрыОбработки.СоздатьПользователяСервиса Тогда
				ИнтеграцияПодсистемБСП.ПриЗавершенииОбработкиПользователяИБ(ПользовательОбъект.Ссылка);
			КонецЕсли;
		КонецЕсли;
	КонецЕсли;
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Обработчики событий подсистемы БСП "РаботаВМоделиСервиса"

// См. ИнтеграцияПодсистемБСП.ПриОпределенииПсевдонимаПользователя
Процедура ПриОпределенииПсевдонимаПользователя(ИдентификаторПользователя, Псевдоним) Экспорт
	
	Если ПользовательЗарегистрированКакНеразделенный(ИдентификаторПользователя) Тогда
		Псевдоним = ПолноеИмяСлужебногоПользователя(ИдентификаторПользователя);
	КонецЕсли;
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Обработчики событий подсистемы БТС "ВыгрузкаЗагрузкаДанных" - выгрузка
// и загрузка пользователей информационной базы.

// См. ВыгрузкаЗагрузкаДанныхПереопределяемый.ПриЗаполненииТиповТребующихАннотациюСсылокПриВыгрузке.
Процедура ПриЗаполненииТиповТребующихАннотациюСсылокПриВыгрузке(Типы) Экспорт
	
	Обработки.ВыгрузкаЗагрузкаДанныхСверткаСсылокНаПользователейВРазделенныхДанных.ПриЗаполненииТиповТребующихАннотациюСсылокПриВыгрузке(
		Типы);
	
КонецПроцедуры

// См. ВыгрузкаЗагрузкаДанныхПереопределяемый.ПриРегистрацииОбработчиковВыгрузкиДанных.
Процедура ПриРегистрацииОбработчиковВыгрузкиДанных(ТаблицаОбработчиков) Экспорт
	
	Обработки.ВыгрузкаЗагрузкаДанныхСверткаСсылокНаПользователейВРазделенныхДанных.ПриРегистрацииОбработчиковВыгрузкиДанных(
		ТаблицаОбработчиков);
	
КонецПроцедуры

// См. ВыгрузкаЗагрузкаДанныхПереопределяемый.ПриРегистрацииОбработчиковЗагрузкиДанных.
Процедура ПриРегистрацииОбработчиковЗагрузкиДанных(ТаблицаОбработчиков) Экспорт
	
	Обработки.ВыгрузкаЗагрузкаДанныхСверткаСсылокНаПользователейВРазделенныхДанных.ПриРегистрацииОбработчиковЗагрузкиДанных(
		ТаблицаОбработчиков);
	
КонецПроцедуры

// См. ВыгрузкаЗагрузкаДанныхПереопределяемый.ПриЗагрузкеПользователяИнформационнойБазы.
Процедура ПриЗагрузкеПользователяИнформационнойБазы(Контейнер, Сериализация, ПользовательИБ, Отказ) Экспорт
	
	Если Не ОбщегоНазначения.РазделениеВключено() Тогда
		
		ПользовательИБ.ПоказыватьВСпискеВыбора = Истина;
		// Добавление роли АдминистраторСистемы пользователю с ролью ПолныеПрава.
		Если ПользовательИБ.Роли.Содержит(Метаданные.Роли.ПолныеПрава) Тогда
			ПользовательИБ.Роли.Добавить(Метаданные.Роли.АдминистраторСистемы);
		КонецЕсли;
		
		ОбновлениеИнформационнойБазыСлужебный.УстановитьФлагОтображенияОписанийДляНовогоПользователя(ПользовательИБ.Имя);
		
	КонецЕсли;
	
КонецПроцедуры

// См. ВыгрузкаЗагрузкаДанныхПереопределяемый.ПослеЗагрузкиПользователяИнформационнойБазы.
Процедура ПослеЗагрузкиПользователяИнформационнойБазы(Контейнер, Сериализация, ПользовательИБ) Экспорт
	
	Если НЕ Контейнер.ДополнительныеСвойства.Свойство("СоответствиеПользователей") Тогда
		Контейнер.ДополнительныеСвойства.Вставить("СоответствиеПользователей", Новый Соответствие());
	КонецЕсли;
	
	Контейнер.ДополнительныеСвойства.СоответствиеПользователей.Вставить(Сериализация.UUID, ПользовательИБ.УникальныйИдентификатор);
	
КонецПроцедуры

// См. ВыгрузкаЗагрузкаДанныхПереопределяемый.ПослеЗагрузкиПользователейИнформационнойБазы.
Процедура ПослеЗагрузкиПользователейИнформационнойБазы(Контейнер) Экспорт
	
	Если Контейнер.ДополнительныеСвойства.Свойство("СоответствиеПользователей") Тогда
		ОбновитьИдентификаторыПользователейИБ(Контейнер.ДополнительныеСвойства.СоответствиеПользователей);
	Иначе
		ОбновитьИдентификаторыПользователейИБ(Новый Соответствие);
	КонецЕсли;
	
	Контейнер.ДополнительныеСвойства.Вставить("СоответствиеПользователей", Неопределено);
	
КонецПроцедуры

#КонецОбласти

#Область ОбработчикиПодписокНаСобытия

Процедура ОбработкаПолученияФормыПользователя(Источник, ВидФормы, Параметры, ВыбраннаяФорма, ДополнительнаяИнформация, СтандартнаяОбработка) Экспорт
	
	Если НЕ ОбщегоНазначения.РазделениеВключено() Тогда
		Возврат;
	КонецЕсли;
	
	Если ВидФормы = "ФормаОбъекта"
		И Параметры.Свойство("Ключ") И НЕ Параметры.Ключ.Пустая() Тогда
		
		УстановитьПривилегированныйРежим(Истина);
		
		Запрос = Новый Запрос;
		Запрос.Текст =
		"ВЫБРАТЬ ПЕРВЫЕ 1
		|	1
		|ИЗ
		|	РегистрСведений.НеразделенныеПользователи КАК НеразделенныеПользователи
		|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Пользователи КАК Пользователи
		|		ПО НеразделенныеПользователи.ИдентификаторПользователяИБ = Пользователи.ИдентификаторПользователяИБ
		|			И (Пользователи.Ссылка = &Ссылка)";
		Запрос.УстановитьПараметр("Ссылка", Параметры.Ключ);
		Если НЕ Запрос.Выполнить().Пустой() Тогда
			СтандартнаяОбработка = Ложь;
			ВыбраннаяФорма = Метаданные.ОбщиеФормы.ИнформацияНеразделенногоПользователя;
			Возврат;
		КонецЕсли;
		
	КонецЕсли;
	
КонецПроцедуры

#КонецОбласти

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

// Только для внутреннего использования.
//
// Возвращаемое значение:
//   см. НовыеДействияСПользователемСервиса
//
Функция ДействияСПользователемСервисаПриНедоступностиНастройкиПользователей()
	
	ДействияСПользователемСервиса = НовыеДействияСПользователемСервиса();
	ДействияСПользователемСервиса.ИзменениеПароля = Ложь;
	ДействияСПользователемСервиса.ИзменениеИмени = Ложь;
	ДействияСПользователемСервиса.ИзменениеПолногоИмени = Ложь;
	ДействияСПользователемСервиса.ИзменениеДоступа = Ложь;
	ДействияСПользователемСервиса.ИзменениеАдминистративногоДоступа = Ложь;
	
	ДействияСКонтактнойИнформацией = ДействияСПользователемСервиса.КонтактнаяИнформация;
	Если ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда
		
		МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
		Для каждого КлючИЗначение Из МодульРаботаВМоделиСервиса.СоответствиеВидовКИПользователяXDTO() Цикл
			ДействияСКонтактнойИнформацией[КлючИЗначение.Ключ].Изменение = Ложь;
		КонецЦикла;
		
	КонецЕсли;
	
	Возврат ДействияСПользователемСервиса;
	
КонецФункции

// Только для внутреннего использования.
//
// Параметры:
//   Пользователь - СправочникСсылка.Пользователи - пользователь.
//
// Возвращаемое значение:
//   см. НовыеДействияСПользователемСервиса
//
Функция ДействияССуществующимПользователемСервиса(Знач Пользователь)
	
	Если Не ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда
		ТекстОшибки = НСтр("ru = 'Работа в модели сервиса не предусмотрена.'");
		ВызватьИсключение ТекстОшибки;
	КонецЕсли;
	
	МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
	
	УстановитьПривилегированныйРежим(Истина);
	Прокси = МодульРаботаВМоделиСервиса.ПолучитьПроксиМенеджераСервиса();
	УстановитьПривилегированныйРежим(Ложь);
	
	ОбъектыДоступа = ПодготовитьОбъектыДоступаПользователя(Прокси.ФабрикаXDTO, Пользователь);
	
	ИнформацияОбОшибке = Неопределено;
	ПраваДоступаОбъектовXDTO = Прокси.GetObjectsAccessRights(ОбъектыДоступа, 
		ИдентификаторСервисаТекущегоПользователя(), ИнформацияОбОшибке);
	ОбработатьИнформациюОбОшибкеWebСервиса(ИнформацияОбОшибке, "GetObjectsAccessRights"); 
	
	Возврат ПраваДоступаОбъектовXDTOВДействияСПользователемСервиса(Прокси.ФабрикаXDTO, ПраваДоступаОбъектовXDTO);
	
КонецФункции

// Только для внутреннего использования.
//
// Возвращаемое значение:
//   см. НовыеДействияСПользователемСервиса
//
Функция ДействияСНовымПользователемСервиса()
	
	ДействияСПользователемСервиса = НовыеДействияСПользователемСервиса();
	ДействияСПользователемСервиса.ИзменениеПароля = Истина;
	ДействияСПользователемСервиса.ИзменениеИмени = Истина;
	ДействияСПользователемСервиса.ИзменениеПолногоИмени = Истина;
	ДействияСПользователемСервиса.ИзменениеДоступа = Истина;
	ДействияСПользователемСервиса.ИзменениеАдминистративногоДоступа = Истина;
	
	ДействияСКИ = ДействияСПользователемСервиса.КонтактнаяИнформация;
	Если ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда
		
		МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
		Для каждого КлючИЗначение Из МодульРаботаВМоделиСервиса.СоответствиеВидовКИПользователяXDTO() Цикл
			ДействияСКИ[КлючИЗначение.Ключ].Изменение = Истина;
		КонецЦикла;
		
	КонецЕсли;
	
	Возврат ДействияСПользователемСервиса;
	
КонецФункции

// Только для внутреннего использования.
//
// Возвращаемое значение:
//   Булево - Истина, если есть право.
//
Функция ЕстьПравоДобавленияПользователей()
	
	Если Не ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда
		ТекстОшибки = НСтр("ru = 'Работа в модели сервиса не предусмотрена.'");
		ВызватьИсключение ТекстОшибки;
	КонецЕсли;
	
	МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
	
	УстановитьПривилегированныйРежим(Истина);
	Прокси = МодульРаботаВМоделиСервиса.ПолучитьПроксиМенеджераСервиса();
	УстановитьПривилегированныйРежим(Ложь);
	
	ОбластьДанных = Прокси.ФабрикаXDTO.Создать(
		Прокси.ФабрикаXDTO.Тип("http://www.1c.ru/SaaS/ApplicationAccess", "Zone"));
	ОбластьДанных.Zone = МодульРаботаВМоделиСервиса.ЗначениеРазделителяСеанса();
	
	ИнформацияОбОшибке = Неопределено;
	ПраваДоступаXDTO = Прокси.GetAccessRights(ОбластьДанных, 
		ИдентификаторСервисаТекущегоПользователя(), ИнформацияОбОшибке);
	ОбработатьИнформациюОбОшибкеWebСервиса(ИнформацияОбОшибке, "GetAccessRights"); 
	
	Для каждого ЭлементСпискаПрав Из ПраваДоступаXDTO.Item Цикл
		Если ЭлементСпискаПрав.AccessRight = "CreateUser" Тогда
			Возврат Истина;
		КонецЕсли;
	КонецЦикла;
	
	Возврат Ложь;
	
КонецФункции

// Только для внутреннего использования.
Процедура ОбновитьОписаниеWebСервисаМенеджераСервиса()
	
	Если НЕ ОбщегоНазначения.РазделениеВключено() Тогда
		Возврат;
	КонецЕсли;
	
	УстановитьПривилегированныйРежим(Истина);
	// Кэш должен быть заполнен до записи пользователя ИБ.
	МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
	МодульРаботаВМоделиСервиса.ПолучитьПроксиМенеджераСервиса();
	УстановитьПривилегированныйРежим(Ложь);
	
КонецПроцедуры

// Параметры:
//  ПользовательИБ - Неопределено, ПользовательИнформационнойБазы
//
// Возвращаемое значение:
//  Булево
//
Функция ВозможенЗапускПриложения(ПользовательИБ)
	
	Возврат ПользовательИБ <> Неопределено
		И Пользователи.ВходВПрограммуРазрешен(ПользовательИБ)
		И Пользователи.ЕстьПраваДляВходаВПрограмму(ПользовательИБ,, Ложь);
	
КонецФункции

// Только для внутреннего использования.
//
// Параметры:
//  ПарольПользователяСервиса - Строка
//                            - Неопределено - сбрасывается в Неопределено при ошибке.
//
// Возвращаемое значение:
//  ТаблицаЗначений:
//   * Идентификатор - УникальныйИдентификатор
//   * Имя - Строка
//   * ПолноеИмя - Строка
//   * Доступ - Булево
//
Функция ПолучитьПользователейСервиса(ПарольПользователяСервиса) Экспорт
	
	Если Не ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда
		ТекстОшибки = НСтр("ru = 'Работа в модели сервиса не предусмотрена.'");
		ВызватьИсключение ТекстОшибки;
	КонецЕсли;
	
	МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
	
	УстановитьПривилегированныйРежим(Истина);
	Прокси = МодульРаботаВМоделиСервиса.ПолучитьПроксиМенеджераСервиса(ПарольПользователяСервиса);
	УстановитьПривилегированныйРежим(Ложь);
	
	ИнформацияОбОшибке = Неопределено;
	Попытка
		СписокПользователей = Прокси.GetUsersList(МодульРаботаВМоделиСервиса.ЗначениеРазделителяСеанса(), );
	Исключение
		ПарольПользователяСервиса = Неопределено;
		ВызватьИсключение;
	КонецПопытки;
	
	ОбработатьИнформациюОбОшибкеWebСервиса(ИнформацияОбОшибке, "GetUsersList"); 
	
	Результат = Новый ТаблицаЗначений;
	Результат.Колонки.Добавить("Идентификатор", Новый ОписаниеТипов("УникальныйИдентификатор"));
	Результат.Колонки.Добавить("Имя", Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(0, ДопустимаяДлина.Переменная)));
	Результат.Колонки.Добавить("ПолноеИмя", Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(0, ДопустимаяДлина.Переменная)));
	Результат.Колонки.Добавить("Доступ", Новый ОписаниеТипов("Булево"));
	
	Для каждого ИнформацияОПользователе Из СписокПользователей.Item Цикл
		СтрокаПользователя = Результат.Добавить();
		СтрокаПользователя.Идентификатор = ИнформацияОПользователе.UserServiceID;
		СтрокаПользователя.Имя = ИнформацияОПользователе.Name;
		СтрокаПользователя.ПолноеИмя = ИнформацияОПользователе.FullName;
		СтрокаПользователя.Доступ = ИнформацияОПользователе.Access;
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

// Только для внутреннего использования.
Процедура ПредоставитьДоступПользователюСервиса(Знач ИдентификаторПользователяСервиса, Знач ПарольПользователяСервиса) Экспорт
	
	Если Не ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда
		ТекстОшибки = НСтр("ru = 'Работа в модели сервиса не предусмотрена.'");
		ВызватьИсключение ТекстОшибки;
	КонецЕсли;
	
	МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
	
	УстановитьПривилегированныйРежим(Истина);
	Прокси = МодульРаботаВМоделиСервиса.ПолучитьПроксиМенеджераСервиса(ПарольПользователяСервиса);
	УстановитьПривилегированныйРежим(Ложь);
	
	ИнформацияОбОшибке = Неопределено;
	Прокси.GrantUserAccess(
		МодульРаботаВМоделиСервиса.ЗначениеРазделителяСеанса(),
		ИдентификаторПользователяСервиса, 
		ИнформацияОбОшибке);
	ОбработатьИнформациюОбОшибкеWebСервиса(ИнформацияОбОшибке, "GrantUserAccess"); 
	
КонецПроцедуры

// Для процедуры ПриЗавершенииОбработкиПользователяИБ.
Процедура АннулироватьДоступПользователяСервиса(ПользовательОбъект)
	
	Если Не ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность")
		Или Не ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.ОбменСообщениями")
		Или НЕ ЗначениеЗаполнено(ПользовательОбъект.ИдентификаторПользователяСервиса) Тогда
		Возврат;
	КонецЕсли;
	
	МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
	МодульСообщенияВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("СообщенияВМоделиСервиса");
	
	НачатьТранзакцию();
	Попытка
		МодульСообщенияУправленияПриложениямиИнтерфейс = ОбщегоНазначения.ОбщийМодуль("СообщенияУправленияПриложениямиИнтерфейс");
		Сообщение = МодульСообщенияВМоделиСервиса.НовоеСообщение(
			МодульСообщенияУправленияПриложениямиИнтерфейс.СообщениеАннулироватьДоступПользователя());
		
		Сообщение.Body.Zone = МодульРаботаВМоделиСервиса.ЗначениеРазделителяСеанса();
		Сообщение.Body.UserServiceID = ПользовательОбъект.ИдентификаторПользователяСервиса;
		
		МодульСообщенияВМоделиСервиса.ОтправитьСообщение(
			Сообщение,
			МодульРаботаВМоделиСервиса.КонечнаяТочкаМенеджераСервиса());
			
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
КонецПроцедуры

// Проверяет, что переданный пользователь соответствует существующему пользователю информационной
// базы в текущей области данных.
//
// Параметры:
//  Пользователь - СправочникСсылка.Пользователи
//
// Возвращаемое значение:
//   Булево
//
Функция ЭтоСуществующийПользовательТекущейОбластиДанных(Знач Пользователь)
	
	УстановитьПривилегированныйРежим(Истина);
	
	Если Не ЗначениеЗаполнено(Пользователь) Тогда
		Возврат Ложь;
	КонецЕсли;
		
	Если Не ЗначениеЗаполнено(Пользователь.ИдентификаторПользователяИБ) Тогда
		Возврат Ложь;
	КонецЕсли;
		
	Возврат ПользователиИнформационнойБазы.НайтиПоУникальномуИдентификатору(Пользователь.ИдентификаторПользователяИБ) <> Неопределено;		
	
КонецФункции

#Область ВспомогательныеПроцедурыИФункции

Функция ИдентификаторСервисаТекущегоПользователя()
	
	Возврат ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Пользователи.ТекущийПользователь(), "ИдентификаторПользователяСервиса");
	
КонецФункции

// Возвращаемое значение:
//  Структура:
//   * ИзменениеПароля - Булево
//   * ИзменениеИмени - Булево
//   * ИзменениеПолногоИмени - Булево
//   * ИзменениеДоступа - Булево
//   * ИзменениеАдминистративногоДоступа - Булево
//   * КонтактнаяИнформация - Соответствие из КлючИЗначение:
//      ** Ключ - СправочникСсылка.ВидыКонтактнойИнформации
//      ** Значение - Структура:
//          *** Изменение - Булево
//
Функция НовыеДействияСПользователемСервиса()
	
	ДействияСПользователемСервиса = Новый Структура;
	ДействияСПользователемСервиса.Вставить("ИзменениеПароля", Ложь);
	ДействияСПользователемСервиса.Вставить("ИзменениеИмени", Ложь);
	ДействияСПользователемСервиса.Вставить("ИзменениеПолногоИмени", Ложь);
	ДействияСПользователемСервиса.Вставить("ИзменениеДоступа", Ложь);
	ДействияСПользователемСервиса.Вставить("ИзменениеАдминистративногоДоступа", Ложь);
	
	ДействияСКонтактнойИнформацией = Новый Соответствие;
	Если ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда
		
		МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
		Для Каждого КлючИЗначение Из МодульРаботаВМоделиСервиса.СоответствиеВидовКИПользователяXDTO() Цикл
			ДействияСКонтактнойИнформацией.Вставить(КлючИЗначение.Ключ, Новый Структура("Изменение", Ложь));
		КонецЦикла;
		
	КонецЕсли;
	
	ДействияСПользователемСервиса.Вставить("КонтактнаяИнформация", ДействияСКонтактнойИнформацией);
	Возврат ДействияСПользователемСервиса;
	
КонецФункции

Функция ПодготовитьОбъектыДоступаПользователя(Фабрика, Пользователь)
	
	Если Не ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда
		ТекстОшибки = НСтр("ru = 'Работа в модели сервиса не предусмотрена.'");
		ВызватьИсключение ТекстОшибки;
	КонецЕсли;
	
	МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
	
	ИнформацияПользователя = Фабрика.Создать(
		Фабрика.Тип("http://www.1c.ru/SaaS/ApplicationAccess", "User"));
	ИнформацияПользователя.Zone = МодульРаботаВМоделиСервиса.ЗначениеРазделителяСеанса();
	ИнформацияПользователя.UserServiceID = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Пользователь, "ИдентификаторПользователяСервиса");
	
	СписокОбъектов = Фабрика.Создать(
		Фабрика.Тип("http://www.1c.ru/SaaS/ApplicationAccess", "ObjectsList"));
		
	ВидыКИ = СписокОбъектов.Item; // СписокXDTO
	ВидыКИ.Добавить(ИнформацияПользователя);
	
	ТипКИПользователя = Фабрика.Тип("http://www.1c.ru/SaaS/ApplicationAccess", "UserContact");
	
	Для каждого КлючИЗначение Из МодульРаботаВМоделиСервиса.СоответствиеВидовКИПользователяXDTO() Цикл
		ВидКИ = Фабрика.Создать(ТипКИПользователя);
		ВидКИ.UserServiceID = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Пользователь, "ИдентификаторПользователяСервиса");
		ВидКИ.ContactType = КлючИЗначение.Значение;
		ВидыКИ.Добавить(ВидКИ);
	КонецЦикла;
	
	Возврат СписокОбъектов;
	
КонецФункции

Функция ПраваДоступаОбъектовXDTOВДействияСПользователемСервиса(Фабрика, ПраваДоступаОбъектовXDTO)
	
	Если Не ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда
		ТекстОшибки = НСтр("ru = 'Работа в модели сервиса не предусмотрена.'");
		ВызватьИсключение ТекстОшибки;
	КонецЕсли;
	
	ТипИнформацияПользователя = Фабрика.Тип("http://www.1c.ru/SaaS/ApplicationAccess", "User");
	ТипКонтактнойИнформации = Фабрика.Тип("http://www.1c.ru/SaaS/ApplicationAccess", "UserContact");
	
	ДействияСПользователемСервиса = НовыеДействияСПользователемСервиса();
	ДействияСКонтактнойИнформацией = ДействияСПользователемСервиса.КонтактнаяИнформация;
	
	МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
	СоответствиеПрав = МодульРаботаВМоделиСервиса.СоответствиеПравXDTOДействиямСПользователемСервиса();
	СоответствиеВидовКИ = МодульРаботаВМоделиСервиса.СоответствиеВидовКИXDTOВидамКИПользователя();
	
	Для каждого ПраваДоступаОбъектаXDTO Из ПраваДоступаОбъектовXDTO.Item Цикл
		
		Если ПраваДоступаОбъектаXDTO.Object.Тип() = ТипИнформацияПользователя Тогда
			
			Для каждого ЭлементСпискаПрав Из ПраваДоступаОбъектаXDTO.AccessRights.Item Цикл
				ДействиеСПользователем = СоответствиеПрав.Получить(ЭлементСпискаПрав.AccessRight);
				ДействияСПользователемСервиса[ДействиеСПользователем] = Истина;
			КонецЦикла;
			
		ИначеЕсли ПраваДоступаОбъектаXDTO.Object.Тип() = ТипКонтактнойИнформации Тогда
			ВидКонтактнойИнформации = СоответствиеВидовКИ.Получить(ПраваДоступаОбъектаXDTO.Object.ContactType);
			Если ВидКонтактнойИнформации = Неопределено Тогда
				ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Неизвестный вид контактной информации: %1'"),
					ПраваДоступаОбъектаXDTO.Object.ContactType);
				ВызватьИсключение ТекстОшибки;
			КонецЕсли;
			
			ДействияСВидомКонтактнойИнформации = ДействияСКонтактнойИнформацией[ВидКонтактнойИнформации];
			Для каждого ЭлементСпискаПрав Из ПраваДоступаОбъектаXDTO.AccessRights.Item Цикл
				Если ЭлементСпискаПрав.AccessRight = "Change" Тогда
					ДействияСВидомКонтактнойИнформации.Изменение = Истина;
				КонецЕсли;
			КонецЦикла;
		Иначе
			ТипXDTO = ПраваДоступаОбъектаXDTO.Object.Тип();
			ПредставлениеТипа = СериализаторXDTO.XMLСтрока(Новый РасширенноеИмяXML(ТипXDTO.URIПространстваИмен, ТипXDTO.Имя));
			ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Неизвестный тип объектов доступа: %1'"), ПредставлениеТипа);
			ВызватьИсключение ТекстОшибки;
		КонецЕсли;
		
	КонецЦикла;
	
	Возврат ДействияСПользователемСервиса;
	
КонецФункции

Функция ПолучитьКодЯзыка(Знач Язык)
	
	Если Язык = Неопределено Тогда
		Возврат "";
	Иначе
		Возврат Язык.КодЯзыка;
	КонецЕсли;
	
КонецФункции

// Обрабатывает информация об ошибке полученную из web-сервиса.
// В случае если передана не пустая информация об ошибке, записывает
// подробное представление ошибки в журнал регистрации и вызывает
// исключение с текстом краткого представления об ошибке.
//
Процедура ОбработатьИнформациюОбОшибкеWebСервиса(Знач ИнформацияОбОшибке, Знач ИмяОперации)
	
	Если ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда
		
		Подсистема = Метаданные.Подсистемы.СтандартныеПодсистемы.Подсистемы.РаботаВМоделиСервиса.Подсистемы.ПользователиВМоделиСервиса; // ОбъектМетаданныхПодсистема
		
		МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
		МодульРаботаВМоделиСервиса.ОбработатьИнформациюОбОшибкеWebСервиса(
			ИнформацияОбОшибке,
			Подсистема.Имя,
			"ManageApplication", // Не локализуется
			ИмяОперации);
		
	КонецЕсли;
	
КонецПроцедуры

// Для процедуры СообщитьЕстьПраваДляВходаВПрограмму.
Функция ПоддерживаютсяСообщенияЕстьПраваДляВходаВПрограмму()
	
	МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
	МодульНастройкиТранспортаОбменаСообщениями = ОбщегоНазначения.ОбщийМодуль(
		"РегистрыСведений.НастройкиТранспортаОбменаСообщениями");
	
	СтруктураНастроек = МодульНастройкиТранспортаОбменаСообщениями.НастройкиТранспортаWS(
		МодульРаботаВМоделиСервиса.КонечнаяТочкаМенеджераСервиса());
	
	ПараметрыПодключенияКМС = Новый Структура;
	ПараметрыПодключенияКМС.Вставить("URL", СтруктураНастроек.WSURLВебСервиса);
	ПараметрыПодключенияКМС.Вставить("UserName", СтруктураНастроек.WSИмяПользователя);
	ПараметрыПодключенияКМС.Вставить("Password", СтруктураНастроек.WSПароль);
	
	ПоддерживаемыеВерсии = ОбщегоНазначения.ПолучитьВерсииИнтерфейса(ПараметрыПодключенияКМС, "UserHandler");
	Если Не ЗначениеЗаполнено(ПоддерживаемыеВерсии) Тогда
		Возврат Ложь;
	КонецЕсли;
	ТекущаяВерсия = ПоддерживаемыеВерсии[ПоддерживаемыеВерсии.ВГраница()];
	
	Возврат ОбщегоНазначенияКлиентСервер.СравнитьВерсии(ТекущаяВерсия, "1.0.0.2") >= 0
	
КонецФункции

#КонецОбласти

#Область РаботаСНеразделеннымиПользователямиИБ

// Возвращает полное имя служебного пользователя для отображения в интерфейсах.
//
// Параметры:
//  Идентификатор - УникальныйИдентификатор
//                - СправочникСсылка.Пользователи
//
// Возвращаемое значение:
//  Строка
//
Функция ПолноеИмяСлужебногоПользователя(Знач Идентификатор = Неопределено) Экспорт
	
	Результат = "<" + НСтр("ru = 'Служебный пользователь %1'") + ">";
	
	Если ЗначениеЗаполнено(Идентификатор) Тогда
		
		Если ТипЗнч(Идентификатор) = Тип("СправочникСсылка.Пользователи") Тогда
			Идентификатор = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Идентификатор, "ИдентификаторПользователяИБ");
		КонецЕсли;
		
		ПорядковыйНомер = Формат(РегистрыСведений.НеразделенныеПользователи.ПорядковыйНомерПользователяИБ(Идентификатор), "ЧДЦ=0; ЧГ=0");
		Результат = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Результат, ПорядковыйНомер);
		
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Проверяет, является ли текущий пользователь ИБ неразделенным.
//
// Возвращаемое значение:
//   Булево
//
Функция ЭтоНеразделенныйПользовательИБ()
	
	Если ПустаяСтрока(ПользователиИнформационнойБазы.ТекущийПользователь().Имя) Тогда
		Возврат Ложь;
	КонецЕсли;
	
	Если Не ОбщегоНазначения.РазделениеВключено() Тогда
		Возврат Ложь;
	КонецЕсли;
	
	Если ПользователиИнформационнойБазы.ТекущийПользователь().РазделениеДанных.Количество() > 0 Тогда
		Возврат Ложь;
	КонецЕсли;
		
	Если ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
		ИдентификаторПользователя = ПользователиИнформационнойБазы.ТекущийПользователь().УникальныйИдентификатор;
		Если Не ПользовательЗарегистрированКакНеразделенный(ИдентификаторПользователя) Тогда
			ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Пользователь с идентификатором %1 не зарегистрирован в качестве неразделенного.'"),
				Строка(ИдентификаторПользователя));
			ВызватьИсключение ТекстОшибки;
		КонецЕсли;
	КонецЕсли;
	
	Возврат Истина;
	
КонецФункции

// При работе в модели сервиса, заносит текущего пользователя в список неразделенных,
// если у него не установлено использование разделителей.
//
Процедура ЗарегистрироватьНеразделенногоПользователяВРегистре()
	
	ИдентификаторПользователяИБ = ПользователиИнформационнойБазы.ТекущийПользователь().УникальныйИдентификатор;
	
	МенеджерЗаписи = РегистрыСведений.НеразделенныеПользователи.СоздатьМенеджерЗаписи();
	МенеджерЗаписи.ИдентификаторПользователяИБ = ИдентификаторПользователяИБ;
	МенеджерЗаписи.Прочитать();
	Если НЕ МенеджерЗаписи.Выбран() Тогда
		НачатьТранзакцию();
		Попытка
			Блокировка = Новый БлокировкаДанных;
			ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.НеразделенныеПользователи");
			Блокировка.Заблокировать();
			
			МенеджерЗаписи.ИдентификаторПользователяИБ = ПользователиИнформационнойБазы.ТекущийПользователь().УникальныйИдентификатор;
			МенеджерЗаписи.ПорядковыйНомер = РегистрыСведений.НеразделенныеПользователи.МаксимальныйПорядковыйНомер() + 1;
			МенеджерЗаписи.ИмяПользователя = ПользователиИнформационнойБазы.ТекущийПользователь().Имя;
			МенеджерЗаписи.Записать();
			
			ЗафиксироватьТранзакцию();
		Исключение
			ОтменитьТранзакцию();
			ВызватьИсключение;
		КонецПопытки;
	ИначеЕсли МенеджерЗаписи.ИмяПользователя <> ПользователиИнформационнойБазы.ТекущийПользователь().Имя Тогда
		НачатьТранзакцию();
		Попытка
			Блокировка = Новый БлокировкаДанных;
			ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.НеразделенныеПользователи");
			ЭлементБлокировки.УстановитьЗначение("ИдентификаторПользователяИБ", ИдентификаторПользователяИБ);
			Блокировка.Заблокировать();
			
			МенеджерЗаписи.ИмяПользователя = ПользователиИнформационнойБазы.ТекущийПользователь().Имя;
			МенеджерЗаписи.Записать();
			ЗафиксироватьТранзакцию();
		Исключение
			ОтменитьТранзакцию();
			ВызватьИсключение;
		КонецПопытки;
	КонецЕсли;
	
КонецПроцедуры

Функция ТекстИсключенияЗаписьНеразделенныхПользователейЗапрещена()
	
	Возврат НСтр("ru = 'Запись неразделенных пользователей при включенном использовании разделителей запрещена.'");
	
КонецФункции

#КонецОбласти

// Обновляет идентификаторы пользователей ИБ в справочнике пользователей, очищает поле ИдентификаторПользователяСервиса.
//
// Параметры:
//  СоответствиеИдентификаторов - Соответствие из КлючИЗначение:
//    * Ключ - УникальныйИдентификатор - исходный идентификатор пользователя ИБ,
//    * Значение - УникальныйИдентификатор - текущий идентификатор пользователя ИБ.
//
Процедура ОбновитьИдентификаторыПользователейИБ(Знач СоответствиеИдентификаторов)
	
	НачатьТранзакцию();
	Попытка
		Блокировка = Новый БлокировкаДанных;
		Блокировка.Добавить("Справочник.Пользователи");
		Блокировка.Заблокировать();
		
		Запрос = Новый Запрос;
		Запрос.Текст =
		"ВЫБРАТЬ
		|	Пользователи.Ссылка КАК Ссылка,
		|	Пользователи.ИдентификаторПользователяИБ КАК ИдентификаторПользователяИБ
		|ИЗ
		|	Справочник.Пользователи КАК Пользователи
		|ГДЕ
		|	Пользователи.ИдентификаторПользователяИБ <> &ПустойИдентификатор";
		Запрос.УстановитьПараметр("ПустойИдентификатор", Новый УникальныйИдентификатор("00000000-0000-0000-0000-000000000000"));
		Результат = Запрос.Выполнить();
		Выборка = Результат.Выбрать();
		Пока Выборка.Следующий() Цикл
			ПользовательОбъект = Выборка.Ссылка.ПолучитьОбъект();
			ПользовательОбъект.ИдентификаторПользователяСервиса = Неопределено;
			ПользовательОбъект.ИдентификаторПользователяИБ 
				= СоответствиеИдентификаторов[Выборка.ИдентификаторПользователяИБ];
			Если ПользовательОбъект.Служебный Тогда
				ПользовательИБ = ПользователиИнформационнойБазы.НайтиПоУникальномуИдентификатору(
					ПользовательОбъект.ИдентификаторПользователяИБ);
				Если ПользовательИБ <> Неопределено
				   И ПользовательИБ.ПоказыватьВСпискеВыбора Тогда
					ПользовательИБ.ПоказыватьВСпискеВыбора = Ложь;
					ПользовательИБ.Записать();
				КонецЕсли;
			КонецЕсли;
			ОбновлениеИнформационнойБазы.ЗаписатьДанные(ПользовательОбъект);	
		КонецЦикла;
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
КонецПроцедуры

#КонецОбласти
